<template>
  <div
    v-if="!initializing"
    :class="['vc-component', ifPrint ? 'vc-print-node' : '']"
    :style="visual.parseStyle(currNode.currStyle)"
    @click="() => eventHandler.trigger('点击事件')"
  >
    <div
      :class="['vc-' + currNode.type, 'vc-comp-item']"
      :style="visual.parseStyle(currNode.currCompStyle)"
    >
      <Component
        v-for="(child, index) in currNode.children"
        :key="index"
        :ref="el => setRefs(el, child)"
        :is="child.compName"
        :node="child"
        :inputParam="visual.getInputParam(child, props.inputParam)"
      />
    </div>
  </div>
</template>

<script setup>
import { getCurrentInstance, inject, nextTick, onMounted, onUnmounted, ref } from 'vue';
import { useVisualCompStore } from '@/visual/js/visual-comp';
import visual from "@/visual/js/visual";
import EventHandler from "@/visual/js/event";

const props = defineProps({
  node: Object,
  inputParam: Object
});
const initializing = ref(true);
const refs = ref({});
const compName = ref('');
const ifPrint = ref(false);
const currNode = ref(props.node);
const visualComp = useVisualCompStore();
const eventHandler = new EventHandler(
  inject('eventHandler', Function, true),
  getCurrentInstance(),
  currNode.value
);

const init = async(styleId) => {
  initializing.value = true;
  visual.initStyle(currNode.value, styleId);
  ifPrint.value = currNode.value.currCompStyle['print'] || false;

  if (currNode.value.type) {
    const res = await visualComp.getVisualComp(currNode.value.type);
    compName.value = res.name;
  }

  for (const child of currNode.value.children) {
    child.compName = await getComp(child.type)
  }
  await nextTick(() => initializing.value = false);
};

const getComp = async(type) => {
  const res = await visualComp.getVisualComp(type);
  return res.name;
}

const setRefs = (el, comp) => {
  if (el) {
    refs.value[comp.id] = el;
  }
};

const validate = (callback) => {
  const promise = new Promise((resolve, reject) => {
    let keys = Object.keys(refs.value);

    if (keys.length === 0) {
      resolve(true);
      return;
    }

    const validates = keys.map(key => {
      const component = refs.value[key];
      if (!component.validate) {
        return Promise.resolve(true);
      }

      return new Promise((innerResolve, innerReject) => {
        component.validate(valid => {
          if (!valid) {
            innerReject();
          } else {
            innerResolve();
          }
        }).catch(innerReject);
      });
    });

    Promise.all(validates)
      .then(() => {
        resolve(true);
      })
      .catch(reject);
  });
  promise.then(valid => callback(valid));
  return promise;
};

const changeStyle = (styleId) => {
  init(styleId);
};

const getData = () => {
  return {};
};

const refresh = async() => {
  initializing.value = true;
  await nextTick(() => initializing.value = false);
};

onMounted(async() => {
  await init();
  await eventHandler.trigger('初始化事件');
});

onUnmounted(() => {
  eventHandler.unregister();
});

defineExpose({ getData, validate, changeStyle, refresh });
</script>
